print("****************元表****************")
-- 任何表变量都可以作为另一个表变量的原表
-- 任何表变量都可以有自己的元表（父）
-- 当子表中进行一些特定操作 会执行元表中的内容
print("****************设置元表****************")
meta = {}
myTable = {}
-- 设置元表函数 setmetatable(子表，元表)
setmetatable(myTable, meta)

print(myTable)
print(meta)

print("****************特定操作****************")
print("****************__tostring****************")
meta2 = {
    -- 当子表要被当做字符串使用时 默认调用元表中的__tostring
    __tostring = function(t)
        return t.name
    end
}

myTable2 = {
    name = "张三2"
}

setmetatable(myTable2, meta2)

print(myTable2)                     -- 张三2

print("****************__call****************")
meta3 = {
    -- 当子表要被当做字符串使用时 默认调用元表中的__tostring
    __tostring = function(t)
        return t.name
    end,
    -- 当子表被当做函数使用时 默认调用元表中__call
    -- 第一个参数默认是子表本身
    __call = function(a, b)
        print(a)
        print(b)
        print("呼叫张三")
    end
}

myTable3 = {
    name = "张三3"
}

setmetatable(myTable3, meta3)

-- 把子表当做函数使用 就会调用元表的__call
myTable3(111, 222)              -- 张三3  111  呼叫张三

myTest = {}
-- myTest()                 -- 报错

print("****************运算符重载****************")

meta4 = {
    -- 运算符重载 当子表使用+运算符时 调用该函数
    -- 运算符+
    __add = function(t1, t2)
        return t1.age + t2.age
    end,
    -- 运算符-
    __sub = function(t1, t2)
        return t1.age - t2.age
    end,
    -- 运算符*
    __mul = function(t1, t2)
        return t1.age * t2.age
    end,
    -- 运算符/
    __div = function(t1, t2)
        return t1.age / t2.age
    end,
    -- 运算符%
    __mod = function(t1, t2)
        return t1.age % t2.age
    end,
    -- 运算符^
    __pow = function(t1, t2)
        return t1.age ^ t2.age
    end,
    -- 运算符==
    __eq = function(t1, t2)
        return t1.age == t2.age
    end,
    -- 运算符<
    __lt = function(t1, t2)
        return t1.age < t2.age
    end,
    -- 运算符<=
    __le = function(t1, t2)
        return t1.age <= t2.age
    end,
    -- 运算符..
    __concat = function(t1, t2)
        return t1.age .. t2.age
    end,
}
myTable4 = {
    age = 3
}

setmetatable(myTable4, meta4)
myTable5 = {
    age = 4
}

setmetatable(myTable5,meta4)

print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)
-- 如果要用条件运算符 来比较两个对象
-- 这两个对象的元表要一致 才能准确调用方法
print(myTable4 == myTable5)
print(myTable4 < myTable5)
print(myTable4 <= myTable5)

print(myTable4 .. myTable5)

print("****************__index****************")

meta6Father = {
    age = 11
}
meta6Father.__index = meta6Father

meta6 = {
    -- age = 1,
    -- __index = {age = 2}
}
-- __index的赋值 最好写在表外面来初始化
meta6.__index = meta6
-- meta6.__index = {age = 2}

myTable6 = {}
setmetatable(meta6, meta6Father)
setmetatable(myTable6, meta6)

-- __index 当子表中 找不到某一个属性时
-- 会到元表中 __index制定的表去找索引
print(myTable6.age)                     -- 11

print("****************__newindex****************")

-- newindex 当赋值时 吐过赋值一个不存在的索引
-- 会把这个赋值到newindex所指的表中 不会修改自己
meta7 = {}
meta7.__newindex = {}
myTable7 = {}
setmetatable(myTable7, meta7)
myTable7.age = 1
print(myTable7.age)                     -- nil
print(meta7.__newindex.age)             -- 1

print("****************get****************")
-- 得到元表 getmetatable(子表) 返回值是元表
print(getmetatable(myTable6))
-- rawget 找自己身上的变量 不会去到元表中找
print(rawget(myTable6, "age"))          -- nil
myTable6.age = 1    
print(rawget(myTable6, "age"))          -- 1

print("****************set****************")
-- rawset 忽略newindex的设置 只会改自己的表
print(myTable7.age)                     -- nil
rawset(myTable7, "age", 2)
print(myTable7.age)                     -- 2